package utils

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
)

//字节段位换算 MB GB TB
func UnitCalc(fileByteSize int64) string  {
	fileCalcSize := float64(fileByteSize)
	parseRes :=""
	unitPos := 0
	units := []string{"B", "KB", "MB", "GB", "TB", "PB","EB","ZB","YB","NB","DB"}
	for {
		unitPos++
		fileCalcSize = float64(fileCalcSize) / 1024
		//fmt.Printf("判断测试 %v < 1024 : %v \n", fileCalcSize, (fileCalcSize<1024))

		if fileCalcSize < 1024 {
			parseRes = fmt.Sprintf("%.3f", fileCalcSize) + units[unitPos]
			break
		}
	}
	return parseRes
}

//判断文件是否存在
func IsFileExist(filename string, filesize int64) bool {
	//判断文件信息是否一致
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		fmt.Println("文件不存在===>可以下载")
		return false
	}
	//判断文件大小是否一致
	if filesize == info.Size() {
		log.Println("文件已存在！", info.Name(), info.Size(), info.ModTime())
		return true
	}

	//删除文件 当文件名一样，但是文件尺寸不一样 就删除重新下载
	delInfo := os.Remove(filename)
	if delInfo != nil {
		log.Println("删除文件失败！", delInfo)
	}

	return false
}

func DelFile(filename string)  {
	//删除文件
	delInfo := os.Remove(filename)
	if delInfo != nil {
		log.Println("删除文件失败！", delInfo)
	}
}

//文件下载 进度实时显示
func DownloadFile(url string, savePath string, loadingInfoCallback func(fileTotalSize, hasDownloadSize int64, isFinish bool)) error {
	var (
		fileTotalSize int64
		hasDownloadSize int64
		buf = make([]byte, 32*1024)
		count int = 0
	)
	//下载临时文件名称
	tmpFilePath := savePath + ".download"
	fmt.Println("临时暂存地址:"+tmpFilePath)
	//创建一个http client
	tr := &http.Transport{
		TLSClientConfig:    &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	//client.Timeout = time.Second * 60 //设置超时时间

	//get方法获取资源
	httpResponse, err := client.Get(url)
	if err != nil {
		log.Printf("Get报错: %v", err)
		return err
	}

	//读取服务器返回的文件大小
	fileTotalSize, err = strconv.ParseInt(httpResponse.Header.Get("Content-Length"), 10, 32)
	if err != nil {
		log.Printf("报错: %v", err)
	}

	//如果文件存在,则不进行下载
	if IsFileExist(savePath, fileTotalSize) {
		log.Printf("IsFileExist报错: %v", err)
		return err
	}

	fmt.Println("文件总大小:", UnitCalc(fileTotalSize))

	//============创建文件===========
	file, err := os.Create(tmpFilePath)
	if err != nil {
		log.Printf("创建文件失败: %v", err)
		return err
	}
	defer file.Close()

	if httpResponse.Body == nil {
		return errors.New("返回的数据为空!!!!")
	}

	defer httpResponse.Body.Close()

	//=============下面是 io.copyBuffer() 的简化版本=============
	for {
		//log.Println("开始下载=====")
		//读取bytes
		readLen, readErr := httpResponse.Body.Read(buf)
		if readLen > 0 {
			//写入bytes
			writeLen, writeErr := file.Write(buf[0:readLen])
			//数据长度大于0
			if writeLen > 0 {
				hasDownloadSize += int64(writeLen)
			}
			//写入出错
			if writeErr != nil {
				err = writeErr
				log.Printf("文件buffer写入报错:%v ", err)
				break
			}
			//读取是数据长度不等于写入的数据长度
			if readLen != writeLen {
				err = io.ErrShortWrite
				log.Println("readLen != writeLen ")
				break
			}
		}

		if readErr != nil {
			if readErr != io.EOF {
				err = readErr
			}
			break
		}
		//不停的把已经下载数据大小 返回给函数
		if count < 166 {
			loadingInfoCallback(fileTotalSize, hasDownloadSize, false)
			count = 0
		}
		count ++
	}

	//=========说明文件已经下载完成了==========
	if err != nil {
		fmt.Println(err)
		return err
	}

	file.Close()
	//文件下载完成 文件去掉download后缀
	err = os.Rename(tmpFilePath, savePath)
	log.Println("==========下载完成============")
	loadingInfoCallback(fileTotalSize, hasDownloadSize, true)
	return nil
}
